using System;
using System.Collections.Generic;
using System.Xml;
using GGEditor.API;

namespace GGEditor.Core.Plugins
{
	public class PluginDependencyTree : IPluginDependencyTreeBuilder
	{
		private List<IPluginDependencyNode> nodes =
			new List<IPluginDependencyNode>();

		public PluginDependencyTree()
		{
			nodes.Add(new PluginDependencyNode()
			{
				FilePath = "",
				PluginPath = "/"
			});
		}

		public void Insert(string pluginPath, string filePath)
		{
			nodes.Add(new PluginDependencyNode()
			{
				FilePath = filePath,
				PluginPath = pluginPath
			});

			nodes.Sort((p1, p2) => p1.PluginPath.CompareTo(p2.PluginPath));
		}

		#region Implementation of IPluginDependencyTree

		public bool IsValid
		{
			get { return true; }
		}

		public IEnumerable<IPluginDependencyNode> NodeLoadingOrder
		{
			get { return nodes; }
		}

		public IEnumerable<string> FileLoadingOrder
		{
			get
			{
				List<string> filePaths = new List<string>();

				foreach (IPluginDependencyNode node in NodeLoadingOrder)
				{
					if (node.FilePath != "" && !filePaths.Contains(node.FilePath))
						filePaths.Add(node.FilePath);
				}

				return filePaths;
			}
		}

		#endregion

		class PluginDependencyNode : IPluginDependencyNodeBuilder
		{
			IList<IPluginDependencyNode> children =
				new List<IPluginDependencyNode>();

			#region Implementation of IPluginDependencyNode

			public string PluginPath { get; set; }

			public string FilePath { get; set; }

			public void Insert(IPluginDependencyNode child)
			{
				children.Add(child);
			}

			public IEnumerable<IPluginDependencyNode> Children
			{
				get { return children; }
			}

			#endregion
		}

		public static IPluginDependencyTree FromFilePaths(IEnumerable<string> filePaths)
		{
			IPluginDependencyTreeBuilder tree = new PluginDependencyTree();

			tree.Insert("", "");

			foreach (string filePath in filePaths)
			{
				FromFilePathsFromFile(filePath, tree);
			}

			//foreach (var node in tree.NodeLoadingOrder)
			//{
			//    Console.WriteLine("DEPNODE: {0}", node.PluginPath);
			//}

			//foreach (var node in tree.FileLoadingOrder)
			//{
			//    Console.WriteLine("FILEDEPNODE: {0}", node);
			//}

			return tree;
		}

		private static void FromFilePathsFromFile(string filePath, IPluginDependencyTreeBuilder tree)
		{
			XmlDocument doc = new XmlDocument();
			doc.Load(filePath);

			foreach (object o in doc.ChildNodes)
			{
				XmlElement e = o as XmlElement;
				if (e == null)
					continue;

				if (e.Name == "Plugin")
					foreach (XmlElement eChild in e.ChildNodes)
					{
						FromFilePathsFromExtension(filePath, tree, eChild);
					}
			}
		}

		private static void FromFilePathsFromExtension(string filePath, IPluginDependencyTreeBuilder tree, XmlElement e)
		{
			if (e == null)
				return;
			if (e.Name == "Extension")
			{
				string path = e.Attributes["path"].InnerText;
				//tree.Insert(path, filePath);
				FromFilePathsFromNodes(filePath, tree, e, path);
			}
		}

		private static void FromFilePathsFromNodes(string filePath, IPluginDependencyTreeBuilder tree, XmlElement e, string parentPath)
		{
			foreach (object o in e.ChildNodes)
			{
				XmlElement eChild = o as XmlElement;
				if (eChild == null)
					continue;

				try
				{
					string name = eChild.Attributes["name"].InnerText;
					string path = PluginPaths.Join(parentPath, name);
					tree.Insert(path, filePath);
					FromFilePathsFromNodes(filePath, tree, eChild, path);
				}
				catch (NullReferenceException) { }
			}
		}
	}
}